#include <iostream>
#include <time.h>// 获取时间
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <stdexcept>// 抛出异常
#include "Logger.h"

using namespace Louis::utility;
using namespace std;

const char* Logger::s_level[LEVEL_COUNT] = {
    "DEBUG",
    "INFO",
    "WARNNING",
    "ERROR",
    "FATAL"
};

Logger *Logger::m_instance = NULL;

Logger::Logger() : m_max(0), m_size(0), m_level(DEBUG) {// Logger构造

}

Logger::~Logger() {// Logger析构
    close();
}

Logger* Logger::instance() {
    if (m_instance == NULL) {
        m_instance = new Logger();
    }
    return m_instance;
}

void Logger::open(const string &filename) {
    m_filename = filename;
    m_fout.open(filename, ios::app);
    if (m_fout.fail()) {
        throw logic_error("Open file failed " + filename);
    }
    m_fout.seekp(0, ios::end);
    m_size = m_fout.tellp();
}

void Logger::close() {
    m_fout.close();
}

void Logger::log(Level level, const char *file, int line, const char *format, ...) {
    if (m_level > level) {
        return;
    }

    if (m_fout.fail()) {
        throw logic_error("Open file failed " + m_filename);
    }

    time_t ticks = time(NULL);
    struct tm *ptm = localtime(&ticks);
    char timestamp[32];
    memset(timestamp, 0, sizeof(timestamp));
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", ptm);

    int size = 0;
    const char *ftm = "%s %s %s:%d ";
    size = snprintf(NULL, 0, ftm, timestamp, s_level[level], file, line);
    if (size > 0) {
        char * buffer = new char[size + 1];
        snprintf(buffer, size + 1, ftm, timestamp, s_level[level], file, line);
        buffer[size] = 0;
        // cout << buffer << endl;
        m_fout << buffer;
        delete [] buffer;
        m_size += size;
    }

    va_list arg_ptr;
    va_start(arg_ptr, format);
    size = vsnprintf(NULL, 0, format, arg_ptr);
    va_end(arg_ptr);
    if (size > 0) {
        char *content = new char[size + 1];
        va_start(arg_ptr, format);
        vsprintf(content, format, arg_ptr);
        va_end(arg_ptr);
        content[size] = 0;
        // cout << content << endl;
        m_fout << content;
        delete [] content;
        m_size += size;
    }

    m_fout << "\n";
    m_fout.flush();

    if (m_max > 0 && m_size >= m_max) {
        rotate();
    }

    // cout << timestamp << endl;
    // cout << file << endl;
    // cout << line << endl;
    // cout << format << endl;
}

void Logger::max(int bytes) {
    m_max = bytes;
}

void Logger::level(int level) {
    m_level = level;
}

void Logger::rotate() {
    close();
    time_t ticks = time(NULL);
    struct tm* ptm = localtime(&ticks);
    char timestamp[32];
    memset(timestamp, 0, sizeof(timestamp));
    strftime(timestamp, sizeof(timestamp), ".%Y-%m-%d_%H-%M-%S", ptm);
    string filename = m_filename + timestamp;
    if (rename(m_filename.c_str(), filename.c_str()) != 0) {
        throw std::logic_error("Rename log file failed: " + string(strerror(errno)));
    }
    open(m_filename);
}